/*
 * @Author: ck
 * @Date: 2023-12-09 15:55:43
 * @LastEditTime: 2023-12-09 21:09:18
 * @Description: axios封装
 */
import axios, { AxiosRequestConfig, InternalAxiosRequestConfig } from "axios";

/**
 * 请求配置
 */
interface RequsetConfig {
  /**
   * @type boolean
   * @default false
   * @description 是否加载方法
   */
  loading?: boolean
  /**
   * @type boolean
   * @default false
   * @description 是否走响应回调-->handleResponse
   */
  isResponse?: boolean
  /**
   * @type boolean
   * @default false
   * @description 是否权限验证
   */
  isAuth?: boolean
}

declare module 'axios' {
  export interface AxiosRequestConfig extends RequsetConfig { }
}

/**
 * @description 默认返回类型
 */
export interface ReturnData {
  code: number,
  data: any
  msg: string
}

export interface httpDefaultConfig<ResponseData> {
  /**
   *@description 默认路径
   */
  baseURL: string
  /**
   * @description 超时时间
   */
  timeout?: number
  /**
   * @description 请求加载回调
   */
  loading?: {
    start: () => void
    end: () => void
  }
  /**
   * @description 请求配置的钩子，可以处理请求配置
   */
  handleReuqset?: (config: ResponseData) => any
  /**
   * @description 相应配置的钩子，可以处理相应数据
   */
  handleResponse?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
  /**
   * 
   * @param error 
   * @description 错误信息
   * @param data 
   * @description 返回的数据
   * @returns 
   */
  fail?: (error: any, data?: ResponseData) => void
  /**
   * 
   * @description 自定义请求头
   */
  header?: {
    /**
     * 
     * @description 自定义公共请求头
     */
    getCommonHeader?: () => any
    /**
     * 
     * @description 自定义鉴权请求头 用来写token 跟其他请求头分开方便管理
     */
    getAuthHeader?: () => any
  }
}

/**
 * 
 * @param T
 * @description httpReq data返回类型
 */
export const httpReq = <ResponseData = ReturnData>(config: httpDefaultConfig<ResponseData>) => {

  const {
    baseURL,
    timeout,
    loading,
    handleReuqset,
    handleResponse,
    header,
    fail
  } = config
  const net = axios.create({
    baseURL: baseURL,
    timeout: timeout || 6e3
  })


  /**
   * 只有加载一个loading 默认加载
   */
  let loadingFlag = 0


  const startLoading = () => {
    loadingFlag++
    loadingFlag && loading?.start()
  }

  const endLoading = () => {
    if (loadingFlag) {
      loadingFlag--
      !loadingFlag && loading?.end()
    }
  }

  net.interceptors.request.use(((request) => {
    const { loading = true, headers, isAuth = true } = request
    loading && startLoading()
    let fomatHeader = headers
    if (header) {
      const authHearder = isAuth ? (header?.getAuthHeader?.() || {}) : {}
      fomatHeader = {
        ...fomatHeader,
        ... {
          ...authHearder,
          ...(header?.getCommonHeader?.() || {})
        }
      }
      // fomatHeader = Object.assign(fomatHeader, {
      //   ...authHearder,
      //   ...(header?.getCommonHeader?.() || {})
      // })
    }

    const req = handleResponse ? handleResponse(request) : {}

    return {
      ...request,
      headers: fomatHeader,
      ...req
    }
  }))

  net.interceptors.response.use((response) => {
    const { data, config } = response
    endLoading()
    try {
      if (handleReuqset && config.isResponse) {
        return handleReuqset(data as ResponseData)
      }
    } catch (error) {
      fail && fail(error, data)
    }
    return response
  }, error => {
    endLoading()
    fail && fail(error)
  })

  /**
   * @param arg 
   * @returns 
   * @description 基础请求方法
   */
  const httpReq = <ResponseData>(arg: AxiosRequestConfig) => {
    return net.request<ResponseData>({
      ...arg
    }) as unknown as ResponseData
  }

  /**
   * @param arg 
   * @returns 
   * @description 基础get请求方法
   */
  const httpGetReq = <T>(arg: AxiosRequestConfig) => {
    return net.request<T>({
      method: 'get',
      ...arg
    }) as unknown as T
  }

  /**
   * @param arg 
   * @returns 
   * @description 基础get请求方法
   */
  const httpPostReq = <T>(arg: AxiosRequestConfig) => {
    return net.request<T>({
      method: 'post',
      ...arg
    }) as unknown as T
  }

  /**
   * @param arg 
   * @returns 
   * @description 基础patch请求方法
   */
  const httpPatchReq = <T>(arg: AxiosRequestConfig) => {
    return net.request<T>({
      method: 'patch',
      ...arg
    }) as unknown as T
  }

  // ...

  return {
    httpReq,
    httpGetReq,
    httpPostReq,
    httpPatchReq
  }
}